#ifndef IO_H
#define IO_H

/*
	 A GAX computer can have up to 31 IO devices. Port 0 is a status word, and is read only. 
	 Each bit indicates the readiness of the corresponding port. If set, the port is ready. 
	 The 0 bit is always set, because you can always read from port 0. 

	 Each IO device should run in its own POSIX thread, to simulate separate physical 
	 devices. 

	 Each IO device has a status word, not visible to GAX, whose meaning is specific to that
	 device, except that a 0 status means the device should stop.
*/
//#define __USE_GNU // define this on GNU systems if you want to use errorchecking mutexes
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sched.h>
#include <pthread.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <math.h>
#include "type.h"

#define PORT_MASK  0x1F
#define STACK_SIZE 4096
#define TTY           1
#define KBD           2
#define RND           3

#define PORT_USEC 1000
#define RND_MAX 0x7FFFFFFFu

#define NANOSLEEP // use nanosleep (3) instead of usleep (obsolete)
#undef SHUFFLE  // shuffle adds a few instructions to permute the sequence (see Knuth)
                // resulting in longer periods. how much longer I don't know. 
#define LAG 32 // I know good multipliers for r in {1, 2, 4, 5, 8, 11, 16, 23, 32}
               // the multiplier for r = 32 is minimal, but still produces a very long period
#ifdef SHUFFLE
	#define RND_TABLE 256 // how many random numbers to keep around for shuffling
#else
	#define RND_TABLE LAG // if we're not shuffling, we only need enough for the lag
#endif
#undef RND_TELL // have the rnd device try to display information about itself to the tty

#ifdef __USE_GNU
	#define MUTEX_INITIALIZER PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
#else
	#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#endif

word get_status (word port);

word read_port (word port);
void write_port (word port, word data);

void start_device (word device, void *arg); 
void stop_device (word device);

/*
	 device functions called from clone () from start_device ()
*/
static void *tty (void *arg); // teletype, ignores arg
static void *kbd (void *arg); // keyboard, ignores arg
static void *rnd (void *arg); // random number generator, arg must be word *, containing seed

/*
	 some functions for interacting with the tty and kbd for debug purposes
*/
void tty_puts (char *s);
void tty_putc (word c);
word kbd_getc (void);

/*
	 tries to be a portable sleep function
*/
static void port_sleep (void);

#endif

